#include <history.h>

#include <time.h> // 為了知道今天的年月
#ifdef WIN32
	#include <winsock2.h>
#else
	#include <netdb.h> // gethostbyname()
	#include <netinet/in.h> // struct sockaddr_in
	#include <sys/socket.h> // socket()
#endif
#include <stdio.h>
#include <string.h> // memset strcmp strstr memcpy
#include <unistd.h> // close




/******************************************************************************
 * 網路傳輸
 *****************************************************************************/
static void CloseConnection(int *sockfd)
{
#ifdef WIN32
	closesocket(*sockfd);
	WSACleanup();
#else
	close(*sockfd);
#endif
}

static int CreateConnection(int *sockfd, char *hostname)
{
#ifdef WIN32
	WSADATA wsaData;
#endif
	struct hostent *host;
	struct sockaddr_in address;

#ifdef WIN32
	if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR)
	{
		WSACleanup();
		return -1;
	}
#endif

	if( !hostname || (*sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1 )
		return -1;

	if( (host=gethostbyname(hostname)) == NULL )
	{
		CloseConnection(sockfd);
		return -1;
	}

	memset(&address, 0, sizeof(address));
	address.sin_family = AF_INET;
	address.sin_port = htons(80);
	address.sin_addr.s_addr = *((unsigned long *)host->h_addr);

	if( connect(*sockfd, (struct sockaddr *)&address, sizeof(struct sockaddr)) == -1 )
	{
		CloseConnection(sockfd);
		return -1;
	}

	return 0;
}

static int SendData(int sockfd, char *output)
{
	if( !output )
		return -1;
		
	send(sockfd, output, strlen(output), 0);
	return 0;
}

static int ReceiveData(int sockfd, char *output, int output_size)
{
	static char *ContentLengthTag = "Content-Length: ";
	int ByteRead, TotalRead=0, ContentLength=65535;
	char *cp, buffer[65535];

	memset(output, 0, output_size);

	while( TotalRead < ContentLength )
	{
		memset(buffer, 0, sizeof(buffer));
		if( (ByteRead=recv(sockfd, buffer, sizeof(buffer)-1, 0)) == -1 )
			return -1;

		cp = buffer;

		if( TotalRead == 0 )
		{
			if( (cp=strstr(buffer, ContentLengthTag)) == NULL )
				return -1;

			cp += strlen(ContentLengthTag);
			sscanf(cp, "%d", &ContentLength);

			if( (cp=strstr(cp, "\r\n\r\n")) == NULL )
				return -1;
			cp += 4;

		}

		ByteRead -= cp - buffer;

		memcpy(output+TotalRead, cp, ByteRead);

		TotalRead += ByteRead;
	}

	return 0;
}






































/******************************************************************************
 * 資料處理
 *****************************************************************************/

static int ParsePacket(char *packet, HISTORY *h, unsigned short *n)
{
	char *cp, *cp1, *cp2, *cp3;
	int i;

	if( !packet || (packet=strstr(packet, "\n ")) == NULL )
		return -1;

	packet += 1;
	i = MAX_HISTORY-1;

	// 一行一行 Parse
	while(*packet)
	{
		if( (cp=strchr(packet, '\n')) != NULL )
			*cp = '\0';

		// 修改 cvs 的雙引號逗號之類的，會比較好切割
		while( (cp1=strchr(packet, '\"')) != NULL )
		{
			if( (cp2=strchr(cp1+1, '\"')) == NULL )
				return -1;

			*cp1 = *cp2 = ' ';
			cp1 += 1;

			while( *cp1 != ' ' )
			{
				if( *cp1 == ',' )
				{
					cp3 = cp1;
					while(1)
					{
						*cp3 = *(cp3+1);
						cp3 += 1;
						if(cp3 == cp2)
							break;
					}
				}
				cp1 += 1;
			}
		}

		// 用逗號切割
		while( (cp1=strchr(packet, ',')) != NULL )
			*cp1 = ' ';

		// 因為取得的資料的順序是從以前到現在（例如 2012/12/01~2012/12/31），所以先填在 table 的最下面，最後再反向填回上面的資料
		sscanf(packet, "%d/%d/%d %d %d %lf %lf %lf %lf"
			, &h[i].year, &h[i].month, &h[i].day
			, &h[i].volume, &h[i].amount
			, &h[i].open, &h[i].high, &h[i].low, &h[i].close
			);
		h[i].year += 1911;
		i -= 1;

		packet += strlen(packet) + 1;
	}

	// 反向填回上面的資料
	if( i < MAX_HISTORY-1 )
	{
		memcpy(&h[*n], &h[i+1], sizeof(HISTORY)*(MAX_HISTORY-1-i));
		*n += MAX_HISTORY-1-i;
	}

	return 0;
}

int GetHistory(char *q, HISTORY *h, unsigned short *n)
{
	char buffer[65535];
	char *host = "www.twse.com.tw";
	time_t t;
	struct tm *tm_p;
	int sockfd, year, month, i, ret;

	time(&t);
	tm_p = localtime(&t);

	year = tm_p->tm_year+1900;
	month = tm_p->tm_mon+1;

	month -= 1;

	*n = 0;
	i=0;
	printf("Downloading %s's history ... ", q);

	while(1)
	{
//		printf("\b\b\b\b\b\b\b%04d/%02d", year, month);
		if( i == 0)
		{
			if( CreateConnection(&sockfd, host) < 0 )
			{
				ret = -1;
				printf("Error: CreateConnection\n");
				break;
			}
		}

		sprintf(buffer,
			"GET /ch/trading/exchange/STOCK_DAY/STOCK_DAY_print.php?genpage=genpage/Report%04d%02d/%04d%02d_F3_1_8_%s.php&type=csv HTTP/1.1\r\n"
			"Host: %s\r\n\r\n"
			,year,month,year,month,q
			,host
		);
		if( SendData(sockfd, buffer) < 0 )
		{
			CloseConnection(&sockfd);
			ret = -1;
			printf("Error: SendData\n");
			break;
		}

		if( ReceiveData(sockfd, buffer, sizeof(buffer)) < 0 || memcmp(buffer, "\"", 1) )//|| !memcmp(buffer, "div>", 4) || !memcmp(buffer, "intval", 6) )
		{
			CloseConnection(&sockfd);
			ret = 0;
			printf("OK\n");
			break;
		}
		ParsePacket(buffer, h, n);

		year = (month==1)?(year-1):(year);
		month = (month==1)?12:(month-1);

		if(i<48)
			i += 1;
		else
		{
			CloseConnection(&sockfd);
			i = 0;
		}
	}

	return ret;
}

